package tpcomp2010.estructura;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Clase que define la matirz transicion utilizada en el algoritmo de subconjunto
 * @author vayala
 * @author tania
 */
public class MatrizTransicion {

    /**
     * La Matriz que representa la clase
     */
    Map<MatrizTransicionKey, ListaNodos> laMatriz;

    /**
     * Class Constructor inicializa la matriz
     */
    public MatrizTransicion() {
        laMatriz = new HashMap<MatrizTransicionKey, ListaNodos>();
    }

    /**
     * Obtiene el valor de la matriz dado un KEY
     * @param clave identificativo de elemento de la matriz
     * @return ListaNodo de la posicion establecida por clave
     */
    public ListaNodos obtenerValor(MatrizTransicionKey clave){
        return obtenerValor(clave.getIndiceNodos(), clave.getIndiceToken());
    }

    /**
     * Obtiene el valor de la matriz dado una ListaNodo y el token
     * @param lista
     * @param token
     * @return La listaNodo de la matriz, null en caso de que no se encuentre
     */
    public ListaNodos obtenerValor(ListaNodos lista, Token token){
        MatrizTransicionKey comparar = new MatrizTransicionKey(lista, token);
        Set<MatrizTransicionKey> claves = laMatriz.keySet();

        for (MatrizTransicionKey claveActual : claves) {
            if(claveActual.compareTo(comparar) == 0){
                return (ListaNodos) laMatriz.get(claveActual);
            }
        }
        return null;
    }

    /**
     * Establece una ralacion entre una ListaNodo y un KEY
     * @param clave el KEY
     * @param valor la ListaNodo
     */
    public void setValor(MatrizTransicionKey clave, ListaNodos valor){
        laMatriz.put(clave, valor);
    }

    /**
     * Convierte la Matriz de TRansicion en un automata
     * @return El automata resultante
     */
    public Automata convertAutomata(){
        Automata nuevoAutomata = new Automata();

        Set<MatrizTransicionKey> keys = laMatriz.keySet();
        for (MatrizTransicionKey clave : keys) {
            ListaNodos valor = obtenerValor(clave);
            
            int id_new_origen = clave.getIndiceNodos().getId();
            int id_new_dest = valor.getId();
            Nodo st_new_origen, st_new_dest;
            
            try{
                 st_new_origen = nuevoAutomata.getNodoById(id_new_origen);
            }catch(Exception ex){
                //No existe el estado entonces creamos 
                st_new_origen = new Nodo(id_new_origen,
                                            clave.getIndiceNodos().contieneInicial(),
                                            clave.getIndiceNodos().contieneFinal(),
                                            false);
                nuevoAutomata.addNodo(st_new_origen);
                if(clave.getIndiceNodos().contieneInicial()){
                    nuevoAutomata.setInicial(st_new_origen);
                }
                if(clave.getIndiceNodos().contieneFinal()){
                    nuevoAutomata.getNodosFinales().insertar(st_new_origen);
                }
                
            }
            
            
            try{
                 st_new_dest = nuevoAutomata.getNodoById(id_new_dest);
            }catch(Exception ex){
                //No existe el estado entonces creamos 
                st_new_dest = new Nodo(id_new_dest,
                                        valor.contieneInicial(), 
                                        valor.contieneFinal(), 
                                        false);
                nuevoAutomata.addNodo(st_new_dest);
                if(valor.contieneInicial()){
                    nuevoAutomata.setInicial(st_new_dest);
                }
                if(valor.contieneFinal()){
                    nuevoAutomata.getNodosFinales().insertar(st_new_dest);
                }
            }

            //Agregamos los enlaces.
            Arista enlace_new = new Arista( st_new_origen, st_new_dest,
                                            clave.getIndiceToken().getValor());
            
            st_new_origen.agregarArista(enlace_new);
        }
               
        return nuevoAutomata;
    }

    /**
     * Formate la matriz para imprimirla
     * @return cadena resultante
     */
    public String imprimirMatriz(){
        String print = "";
        String tipoClave="", tipoLista="";
        Set<MatrizTransicionKey> keys = laMatriz.keySet();
        
        for (MatrizTransicionKey clave : keys) {
            ListaNodos lista = obtenerValor(clave);
            tipoClave="";
            tipoLista="";
            if (lista.contieneInicial())
                tipoLista += " (i) ";

            if (lista.contieneFinal())
                tipoLista += " (f) ";

            if (clave.getIndiceNodos().contieneInicial())
                tipoClave += " (i) ";

            if (clave.getIndiceNodos().contieneFinal())
                tipoClave += " (f) ";


            print += "\n" + tipoClave +clave.getIndiceNodos().imprimir() +
                    " ---- " + clave.getIndiceToken().getValor() +
                    " ---- " + tipoLista + lista.imprimir();
        }
        return print;
    }

}

